﻿// ------------------------------------------------------------------------
// 项目名称：Canroc.Net 
// 版权归属：Canroc（https://gitee.com/canroc）
//
// 许可证信息
// Canroc.Net项目主要遵循 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-APACHE 文件。
//
// 使用条款：
// 1.使用本项目应遵守相关法律法规和许可证的要求。
// 2.不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动。
// 3.任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任
//
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
//
// 其他重要信息
// Canroc.Net 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// ------------------------------------------------------------------------

using Canroc.Net.Core.Const;
using Canroc.Net.SystemService.RedisService;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing;
using System.Security.Claims;

namespace Canroc.Net.Web.Core.Handlers;

/// <summary>
///     JWT鉴权
/// </summary>
public class JwtHandler : AppAuthorizeHandler
{
    /// <summary>
    ///     重写 Handler 添加自动刷新
    /// </summary>
    /// <returns></returns>
    public override async Task HandleAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext)
    {
        // 自动刷新Token
        if (JWTEncryption.AutoRefreshToken(context, context.GetCurrentHttpContext()))
        {
            await AuthorizeHandleAsync(context);
        }
        else
        {
            context.Fail(); // 授权失败
        }
    }

    /// <summary>
    ///     授权判断逻辑，授权通过返回 true，否则返回 false
    /// </summary>
    /// <param name="context"></param>
    /// <param name="httpContext"></param>
    /// <returns></returns>
    public override async Task<bool> PipelineAsync(AuthorizationHandlerContext context,
        DefaultHttpContext httpContext)
    {
        var redisService = App.GetRequiredService<IRedisService>();
        var session =
            await redisService.HashGetAsync<SessionRedisModel>("session", UserManager.Account);
        if (session is null)
        {
            return false;
        }

        // 更新刷新后的Token
        var newAccessToken = httpContext.Response.Headers["access-token"].ToString();
        if (!newAccessToken.IsNullOrEmpty())
        {
            session.AccessToken = newAccessToken;
            _ = await redisService.HashSetAsync("session", UserManager.Account, session);
        }

        // 更新httpContext中User的鉴权信息
        httpContext.User.AddIdentity(new ClaimsIdentity([
            new Claim(ClaimConst.ClaimUserId, session.UserId.ToString())
        ]));

        // 资源策略验证
        return CheckAuthenticationAsync(httpContext, session.Routes);
    }

    /// <summary>
    ///     资源策略验证
    /// </summary>
    /// <param name="httpContext">请求上下文</param>
    /// <param name="routes">资源路由列表</param>
    /// <returns></returns>
    private static bool CheckAuthenticationAsync(DefaultHttpContext httpContext, List<string>? routes)
    {
        // 管理员跳过判断
        if (UserManager.IsSuperAdmin) return true;

        // 如果所属资源为空，直接返回false
        if (routes is null || routes.Count == 0) return false;

        // 路由名称
        var endpointFeature = httpContext.HttpContext.Features.Get<IEndpointFeature>();
        if (endpointFeature is null) return false;

        var routeEndpoint = endpointFeature.Endpoint as RouteEndpoint;
        // 路由表达式（路径）
        var routePattern = routeEndpoint?.RoutePattern;
        // 验证用户是否有权限
        return routePattern?.RawText is not null &&
               routes.Contains(routePattern.RawText);
    }
}